using System;
using System.Linq;
using System.Net;
using BSDS.Core.Data.Local.Schema;
using BSDS.Core.Data.Remote.Account;
using BSDS.Core.Infrastructure.Configuration;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Infrastructure.RemoteCommunication;

namespace BSDS.Core.Model.Services
{
    public class AccountService
    {
        private const string InfoQueryTemplate = "http://spatial.virtualearth.net/REST/v1/data?&key={0}";
        private const string DeleteQueryTemplate = "http://spatial.virtualearth.net/REST/v1/data/{0}/{1}?key={2}";
        private const string DownloadSchemaQueryTemplate = "http://spatial.virtualearth.net/REST/v1/data/{0}/{1}/$metadata?key={2}";

        private readonly IBingKey bingKey;
        private readonly AccountRequestSerializer serializer;
        private readonly ServiceClient serviceClient;
        private readonly XmlSchemaSerializer schemaSerializer;
        private readonly Logger logger;

        internal AccountService(AccountRequestSerializer serializer, ServiceClient serviceClient, 
            XmlSchemaSerializer schemaSerializer, Logger logger, IBingKey bingKey)
        {
            this.serializer = serializer;
            this.serviceClient = serviceClient;
            this.schemaSerializer = schemaSerializer;
            this.logger = logger;
            this.bingKey = bingKey;
        }

        public DataSourceInfo[] GetAccountGeneralInforamtion()
        {
            logger.Log("Downloading data sources list.");

            var result = serviceClient.SendRequest(string.Format(InfoQueryTemplate, bingKey), "GET");

            if(result.Status != HttpStatusCode.OK)
            {
                logger.Log("Error getting data sources list.", result);

                throw new Exception("Cannot download data sources list.");
            }

            var dataSourceInfos = serializer.ParseDataSourcesXml(result.Content);

            return dataSourceInfos.ToArray();
        }

        public DataSourceInfo GetDataSourceInformation(string dataSourceName)
        {
            logger.Log("Downloading information for data source: " + dataSourceName);

            var result = serviceClient.SendRequest(string.Format(InfoQueryTemplate, bingKey), "GET");

            if(result.Status != HttpStatusCode.OK)
            {
                logger.Log("Error getting data source info.", result);

                throw new Exception("Cannot download info for data source: " + dataSourceName);
            }

            var dataSourceInfos = serializer.ParseDataSourcesXml(result.Content);

            if (!dataSourceInfos.Any(ds => ds.Name == dataSourceName))
            {
                throw new Exception("No data source exists with name: " + dataSourceName);
            }

            return dataSourceInfos.First(ds => ds.Name == dataSourceName);
        }

        public string DeleteDataSource(string accessId, string dataSourceName)
        {
            logger.Log("Deleting data source: " + dataSourceName);

            var uri = string.Format(DeleteQueryTemplate, accessId, dataSourceName, bingKey);
            var result = serviceClient.SendRequest(uri, "DELETE");

            if(result.Status != HttpStatusCode.Accepted)
            {
                logger.Log("Error deleting data source.", result);
            }

            return Enum.GetName(typeof (HttpStatusCode), result.Status);
        }

        public string DownloadSchema(string dataSourceName)
        {
            var sourceInfo = GetDataSourceInformation(dataSourceName);
            var uri = string.Format(DownloadSchemaQueryTemplate, sourceInfo.AccessId, dataSourceName, bingKey);

            var result = serviceClient.SendRequest(uri, "GET");

            if(result.Status != HttpStatusCode.OK)
            {
                logger.Log("Error downloading schema.", result);
            }

            schemaSerializer.Serialize(result.Content, dataSourceName + ".xsd");

            return Enum.GetName(typeof(HttpStatusCode), result.Status);
        }

        public bool DataSourceExists(string dataSourceName)
        {
            var dataSources = GetAccountGeneralInforamtion();

            return dataSources.Any(ds => ds.Name.ToLower() == dataSourceName.ToLower());
        }
    }
}